package com.tank.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * User: SuQiEr
 * Date:2017/9/17 0017
 * Time: 下午 4:42
 * To change this template use File | Settings | File Templates.
 */
public class SocketChannelTest2 {

    public static final Map<String,SocketChannel> clientMap = new HashMap<>();

    public static void main(String[] args) throws Exception {

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //非阻塞
        serverSocketChannel.configureBlocking(false);
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(8999));
        //通道注册到选择器
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();
            selector.selectedKeys().forEach(item ->{

                SocketChannel client = null;
                //可连接
                if(item.isAcceptable()){
                    ServerSocketChannel ssc = (ServerSocketChannel)item.channel();
                    try {
                        client = ssc.accept();
                        client.configureBlocking(false);
                        client.register(selector,SelectionKey.OP_READ);
                        clientMap.put(UUID.randomUUID().toString(),client);
                        selector.selectedKeys().remove(item);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                //可读
                }else if(item.isReadable()){
                    client = (SocketChannel)item.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    try {
                        //读
                        byteBuffer.clear();
                        int readLength = 0;
                        try {
                            readLength = client.read(byteBuffer);
                        }catch (Exception ex){
                            System.out.println("客户端发生强制关闭 remote:"+client.getRemoteAddress());
                            item.cancel();
                            client.socket().close();
                            client.close();
                            return;
                        }

                        if(readLength > 0){
                            //写
                            byteBuffer.flip();
                            Charset charset = Charset.forName("UTF-8");
                            String receiveMessage = String.valueOf(charset.decode(byteBuffer).array());
                            System.out.println("receiveMessage:"+receiveMessage);

                            //获取当前客户端id
                            String currentKey = getClientKey(client);

                            //遍历发送当前所有客户端
                           writeAllClient(currentKey,receiveMessage);
                        }
                        selector.selectedKeys().remove(item);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });



        }
    }

    private final static String getClientKey(SocketChannel client){
        for (Map.Entry<String, SocketChannel> cli :clientMap.entrySet()) {
            if(cli.getValue() == client){
                return cli.getKey();
            }
        }
        return null;
    }

    public static final void writeAllClient(String currentKey,String receiveMessage) throws IOException {
        for (Map.Entry<String, SocketChannel> cli :clientMap.entrySet()){
            if(cli.getValue().isConnected()){
                ByteBuffer writeBuf = ByteBuffer.allocate(1024);
                writeBuf.put((currentKey+":"+receiveMessage+"\n").getBytes());
                writeBuf.flip();
                cli.getValue().write(writeBuf);
            }
        }
    }
}
